package simpackNew;

public class User {
    public int userId;
    // public int classType;		// Type of the class
    public int requestCount;		// Amount of requests that was done by a user 
    public final double contractedResponseTime;
    public double meanResponseTime;	// Current mean response time offered
    public long satisfied;		// Percentage of times where the contracted average was fulfilled, with a acceptable deviation
    public long latenciesBelowAverage;	// Amount of requests that satisfied the contract, with a acceptable deviation
    
    
    /**
     * @param classType - Type of the class
     * @param userId - ID of a user
     * @param cRt - Contracted Response Time 
     * */
    public User(int userId, double cRt) {
    // public User(int classType, int userId, double cRt) {
	this.userId = userId;
	// -> this.classType = classType;
	this.contractedResponseTime = cRt;
	this.requestCount = 0;
	this.meanResponseTime = 0.0;
	this.satisfied = 0;
	this.latenciesBelowAverage = 0;
    }
    
    
    /**
     * Update user's data, like current mean response time and
     * the amount of requests submited to the system.
     * */
    public void update(double timeStamp) {
	double responseTime = Sim.time() - timeStamp;

	// Arithmetic mean
	meanResponseTime = ((meanResponseTime * requestCount) + responseTime) / (requestCount + 1);
	
//	int N = 100;
//	double K = 2 / (double) (N + 1);
//	// Teste
//	meanResponseTime = responseTime * K + meanResponseTime * (1 - K);
//	System.out.println("r:" + responseTime + " - m:" + meanResponseTime);

	// Historic basead mean
	/**
	 *     Mt = Mt-1 * (1 - alfa) + (custoAtual * alfa)   alfa: 0.05 - 0.5, 10x
	 * */
//	meanResponseTime = meanResponseTime * (1 - Const.ALFA) + responseTime * Const.ALFA;
//	meanResponseTime = meanResponseTime * alfa + responseTime * (1 - alfa);

	if ((responseTime <= (contractedResponseTime * (1 + Const.DEVIATION_ACCEPTABLE)))) {
	    latenciesBelowAverage++;
	}
	if ((meanResponseTime <= (contractedResponseTime * (1 + Const.DEVIATION_ACCEPTABLE)))) {
	    satisfied++;
	}
	requestCount++;
    }
    
    /**
     *  Retorna o atraso m�ximo de uma requisi��o de modo
     *  a atender  os  requisitos  de  m�dia contratados.
     *     => Equacao:
     *     	(mRa * nR) + tE + x   tRC
     *     	------------------- <=
     *     	       nR + 1
     *     
     *     , em que
     *     
     *     - mRa: m�dia de resposta atual;
     *     - nR: n�mero de requisi��es solicitadas;
     *     - tE: tempo de espera da requisi��o atual;
     *     - x : deadLine da requisi��o atual;
     *     - tRC: tempo de resposta contratado pelo usu�rio.
     */
    public double getDeadline(TOKEN t) {
	double Tr = (contractedResponseTime * (requestCount + 1)) - (meanResponseTime * requestCount) - (Sim.time() - t.timeStamp);
	
	if (Tr < 0)
	    return (Tr / t.load);
	return (Tr * t.load);

//	return (Tr);
	
	
//	return (((Tr + t.load) * (Tr + t.load)) / t.load);
//	return (Tr * Math.pow(t.load, 0.0000005));
//	return (Math.pow(Tr * t.load, 1));
//	if(Tr > 0)
//	    return (Math.pow(t.load, 2) * Tr);
//	double std = Sim.variance;
//	double std = 30.0;
//	return(Tr / Math.exp(-(Math.pow(t.load,2)/(2 * std))));
//	double beta = 10.0;
//	return((1/Math.exp(-beta * t.load)) * Tr);
//	return (Math.tanh(0.001 * (Tr - t.load)) * 1000.0);
//	if(Tr < 0)
//	    return (Math.log(Math.abs(Tr + t.load)/Math.abs(Tr + t.load)));
//	return (Math.log(Tr + t.load));
//	return (Tr * (Math.pow(t.load, 3) + t.timeStamp));
//	return (Tr);

//	return ((contractedResponseTime - meanResponseTime * Const.ALFA - (Sim.time() - t.timeStamp) * (1 - Const.ALFA)) / Const.ALFA);
	
//	return (((contractedResponseTime - (meanResponseTime * alfa)) / (1 - alfa)) - (Sim.time() - t.timeStamp));
    }
}